---
title: Reader API
summary: >-
  The Reader API is a Node.js API that lets you read Keystatic content from a
  storage of your own choice.
---
The Reader API is a Node.js API that lets you *read* Keystatic content from a storage of your own choice.
The storage can be any local directory / GitHub repository, and does not need to be the same as the one defined in the Keystatic config.

{% aside icon="⚠️" %}
The reader API code is meant to run on the server, and not in the browser. Be sure to use it accordingly.
{% /aside %}

## Usage

### Local Directory

To read from local storage, import the `createReader` function, as well as your Keystatic config file:

```javascript
import { createReader } from '@keystatic/core/reader';
import keystaticConfig from 'relative/path/to/your/keystatic.config';
```

You can then create a new `reader` by calling `createReader` and passing it two arguments:

1. Path to the root of your content repository
1. The Keystatic config

```javascript
const reader = createReader(process.cwd(), keystaticConfig);
```

### GitHub Repository

To read from GitHub, import the `createGitHubReader` function, as well as your Keystatic config file:

```javascript
import { createGitHubReader } from '@keystatic/core/reader/github';
import keystaticConfig from 'relative/path/to/your/keystatic.config';
```

You can then create a new `reader` by calling `createGitHubReader` and passing it the following arguments:

1. The Keystatic config
1. An options object containing:
   - `repo`: The name of the content repository on GitHub (e.g. `Thinkmill/keystatic-data`)
   - `token`: The Personal Access Token that allows read access to the repository. This is different from your GitHub App Client ID / Secret in `.env`.
     For information on how to generate PATs, see [GitHub's documentation](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens).

```javascript
const reader = createGitHubReader(keystaticConfig, {
    repo: 'Thinkmill/keystatic-data',
    token: process.env.GITHUB_PAT,
});
```

---

## Reading from collections

You can get an **array of slugs** for a given collection with:

```javascript
const slugs = await reader.collections.{collectionName}.list();

// Example
const slugs = await reader.collections.posts.list();
```

You can get the data for a specific collection entry with:

```javascript
const entry = await reader.collections.{collectionName}.read(slug);

// Example
const post = await reader.collections.post.read(slug);
```

You can get an array of objects containing **both** slug and entry data for a collection with:

```javascript
const entries = await reader.collections.{collectionName}.all();

// Example
const posts = await reader.collections.blog.all();
```

---

## Reading from singletons

You can get the data for a specific singleton with:

```ts
const data = await reader.singletons.{singletonName}.read();

// Example
const navigation = await reader.singletons.navigation.read();
```

**Remember:** this code cannot run in the browser, as it's using some Node.js APIs.

Good places to use the Reader API are:

- `getStaticProps` in **Next.js (Pages Router)**
- The frontmatter in **Astro** files
- The `loader()` function in **Remix**
- React **Server Components**

---

## Data from linked files

If your collection or singleton contains a `document` field, that field will be returned as an asynchronous function that you'll need to call to get the data:

```ts
// The `posts` collection has a `document` field named `content`
const post = await reader.collections.posts.read(slug);

// Get the content data
const content = await post.content()
```

If you'd rather get the `document` field data immediately, you can pass `resolveLinkedFiles: true` as an option when reading the entry:

```ts
await reader.collections.posts.read(slug, { resolveLinkedFiles: true });
```

---

## Using TypeScript

The Reader API exports an `Entry` type, which is useful when you need to define what props a UI component should receive:

```ts
import { Entry } from '@keystatic/core/reader';
import keystaticConfig from '../../keystatic.config';

type MovieProps = Entry<typeof keystaticConfig['collections']['movies']>

export function Movie(props: MovieProps) {
  // ...
}
```

If your data was read using the `resolvedLinkedFiles` option, you can use the `EntryWithResolvedLinkedFiles` type instead:

```ts
import { EntryWithResolvedLinkedFiles } from '@keystatic/core/reader';
import keystaticConfig from '../../keystatic.config';

type MovieProps = EntryWithResolvedLinkedFiles<typeof keystaticConfig['collections']['movies']>
```

---

## Rendering content from the document field

The `document` field returns a JSON object with complex structured data. It can be a lot of work to turn this data object as HTML to render it on a page.

Luckily, Keystatic also provides a `DocumentRenderer` that does all the heavy lifting for you, and is highly customisable.

---

## Screencast walk-through

This segment of the [Keystatic Mini-Course on YouTube](https://www.youtube.com/playlist?list=PLHrxuCR-0CcSmkyLcmdV7Ruql8DTm644k) may help understand how the Reader API works:

{% embed
   mediaType="video"
   embedCode="<iframe src=\"https://www.youtube.com/embed/8831JbFOCN4?si=mDDK52Nlhg4v1v9x\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen></iframe>" /%}

---

## Type signature

Find the latest version of the `Reader` type signature at: [https://docsmill.dev/npm/@keystatic/core@latest#/.reader.Reader](https://docsmill.dev/npm/@keystatic/core@latest#/reader.Reader)
